package com.harry.decoupling.defi.tool;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections4.SetUtils;
import org.apache.commons.lang3.StringUtils;

import com.harry.decoupling.defi.proxy.GenericSrvProxy;
import com.harry.resource.inner.entity.InnerDict;
import com.harry.resource.inner.entity.InnerDictGroup;
import com.harry.utility.BeanCtxUtils;
import com.harry.utility.InnerUtils;
import com.harry.utility.InitializeUtil;
import com.harry.utility.query.InnerCriteria;

/**
 * 数据字典管理器
 */
public interface DictManager {

	Set<String> dictGroupNames() throws Exception;

	Map<String, String> dictGroup(String dictGroupName) throws Exception;

	String dict(String dictGroupName, String code) throws Exception;

	void add(String dictGroupName, String code, String value) throws Exception;

	static void entityTypeInit() throws Exception {
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		Set<Class<?>> classes = InnerUtils.getAllEntities();
		List<InnerDictGroup> list = srv.query(InnerDictGroup.class, new InnerCriteria("eq", "name", "ENTITY_TYPE"), null);
		InnerDictGroup entityTypeGroup;
		if (list.size() == 1) {
			entityTypeGroup = list.get(0);
		} else if (list.size() == 0) {
			entityTypeGroup = null;
		} else {
			throw new Exception("Duplicate Group Name ENTITY_TYPE");
		}
		Set<String> forInserts;
		Integer maxSno;
		Set<String> currentCodeSet = classes.stream().map(c -> c.getSimpleName()).collect(Collectors.toSet());
		if (entityTypeGroup == null) {
			forInserts = currentCodeSet;
			entityTypeGroup = new InnerDictGroup();
			entityTypeGroup.setName("ENTITY_TYPE");
			srv.save(entityTypeGroup);
			maxSno = 0;
		} else {
			List<InnerDict> existDictTypeList = srv.query(InnerDict.class, new InnerCriteria("eq", "dictGroup.name", "ENTITY_TYPE"), null);
			Set<String> existCodeSet = existDictTypeList.stream().map(d -> d.getCode()).collect(Collectors.toSet());
			if (!SetUtils.isEqualSet(existCodeSet, currentCodeSet)) {
				forInserts = SetUtils.difference(currentCodeSet, existCodeSet);
				Set<String> forDeletes = SetUtils.difference(existCodeSet, currentCodeSet);
				Set<String> forIntercs = SetUtils.intersection(existCodeSet, currentCodeSet);
				String maxSnoStr = forIntercs.size() == 0 ? "00" : existDictTypeList.stream().filter(d -> forIntercs.contains(d.getCode())).max((a, b) -> String.CASE_INSENSITIVE_ORDER.compare(a.getCode(), b.getCode())).get().getSno();
				maxSno = Integer.parseInt(maxSnoStr, 10);
				srv.deleteByCriteria(InnerDict.class, new InnerCriteria("eq", "dictGroup.name", "ENTITY_TYPE", "in", "code", forDeletes));
			} else {
				forInserts = SetUtils.emptySet();
				maxSno = null;
			}
		}
		for (String temp : forInserts) {
			InnerDict dict = new InnerDict();
			dict.setValue(temp);
			dict.setCode(temp);
			dict.setSno(StringUtils.leftPad((++maxSno) + "", 3, "0"));
			dict.setDictGroup(entityTypeGroup);
			srv.save(dict);
		}
	}

	static void defaultInit() throws Exception {
		new Init03xInnerDict("inner/Init03xInnerDict.resource").execInitlize();
	}

	static void initDictCache() throws Exception {
		DictManager dm = BeanCtxUtils.getBeanByType(DictManager.class);
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		List<InnerDict> dictList = srv.query(InnerDict.class, new InnerCriteria(), null);
		for (InnerDict temp : dictList) {
			dm.add(temp.getDictGroup().getName(), temp.getCode(), temp.getValue());
		}
	}

	static class Init03xInnerDict {

		public Init03xInnerDict(String src) {
			this.src = src;
		}

		public void execInitlize() throws Exception {
			postDicts();
		}

		private Boolean needInit;

		private String src;

		private InnerDictGroup dictGroup;

		private int sno = 0;

		private void postDicts() throws Exception {
			try {
				InitializeUtil.forEachLine(this.src, dataStr -> {
					if (this.needInit == null) {
						GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
						this.needInit = 0 == srv.countByCriteria(InnerDictGroup.class, new InnerCriteria("eq", "name", dataStr.trim()));
					}
					if (!this.needInit) {
						throw STOP_INIT_EXCEPTION;
					}
					if (dataStr.indexOf(",") == -1) {
						// 1. INIT SNO
						this.sno = 1;
						// 2. INIT GROUP
						this.dictGroup = (new InnerDictGroup());
						this.dictGroup.setName(dataStr.trim());
						// 3. SAVE GROUP
						InitializeUtil.forceSave(this.dictGroup);
					} else {
						int splitIndex = dataStr.indexOf(",");
						String code = dataStr.substring(0, splitIndex);
						String value = dataStr.substring(splitIndex + 1, dataStr.length());
						InnerDict dict = new InnerDict();
						dict.setCode(code);
						dict.setValue(value);
						dict.setDictGroup(this.dictGroup);
						dict.setSno(StringUtils.leftPad(this.sno + "", 3, '0'));
						InitializeUtil.forceSave(dict);
						this.sno++;
					}
				});
			} catch (Exception e) {
				if (e != STOP_INIT_EXCEPTION) {
					throw e;
				}
			}

		}
	}

	static Exception STOP_INIT_EXCEPTION = new Exception();
}
